{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "id": "BQ_52GTV6jJy"
   },
   "source": [
    "# OmniSafe Tutorial - Getting Started\n",
    "\n",
    "OmniSafe: https://github.com/PKU-Alignment/omnisafe\n",
    "\n",
    "Documentation: https://omnisafe.readthedocs.io/en/latest/\n",
    "\n",
    "Safety-Gymnasium: https://www.safety-gymnasium.com/\n",
    "\n",
    "[Safety-Gymnasium](https://www.safety-gymnasium.com/) is a highly scalable and customizable Safe Reinforcement Learning library, aiming to deliver a good view of benchmarking Safe Reinforcement Learning (Safe RL) algorithms and a more standardized setting of environments. \n",
    "\n",
    "\n",
    "## Introduction\n",
    "\n",
    "在这个教程当中，我们将介绍OmniSafe的一些基本用法，通过简单易懂的例子，让OmniSafe尽可能迅速且可靠地服务于用户的研究和生产任务。通过本章和后续几章的tutorial的介绍，希望帮助您建立起对OmniSafe的特性和设计理念较为全面的了解。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "v8ZS9NZsTBia"
   },
   "outputs": [],
   "source": [
    "# Install from PyPI. if you already have OmniSafe installed, please ignore the code in this cell.\n",
    "!pip install omnisafe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "X_QurlxZ0jDh"
   },
   "outputs": [],
   "source": [
    "# Install OmniSafe and dependencies from source\n",
    "## if you already have OmniSafe installed, please ignore the code in this cell.\n",
    "## Clone the repo\n",
    "!git clone https://github.com/PKU-Alignment/omnisafe\n",
    "%cd omnisafe\n",
    "\n",
    "## Install OmniSafe\n",
    "!pip install -e ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rnq3f13hNR1V"
   },
   "source": [
    "## Basic Usage Examples"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "u1dg7h99Nq83"
   },
   "source": [
    "### Train from default configs\n",
    "\n",
    "下面我们通过`4`行代码调用PPOLag训练一个SafeRL agent。\n",
    "\n",
    "OmniSafe在开发过程中已经经过了详尽的测试和调整，**默认的超参数**旨在通过**最少的调整**和**tricks**在尽可能多的基准环境上达到最好的整体效果。第一次使用时，不妨忽略所有细节，先享受一下开箱即用的快乐。\n",
    "\n",
    "只需要指定`env_id`和`algo`，就可以快速开始您的SafeRL旅程。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "cj2GjYy2PqZ_"
   },
   "outputs": [],
   "source": [
    "import omnisafe\n",
    "\n",
    "\n",
    "env_id = 'SafetyPointGoal0-v0'\n",
    "\n",
    "agent = omnisafe.Agent('PPOLag', env_id)\n",
    "agent.learn()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "fIiALZst13F0"
   },
   "source": [
    "运行的结果会默认保存到您运行python脚本的目录下。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "id": "F2MZiwk02RWp"
   },
   "source": [
    "### Train from custom dict\n",
    "\n",
    "强化学习的超参对性能有很大影响，当浅尝了默认的设置之后，面对具体的问题，您可以通过字典来指定参数取值，探索新的见解和方法。[默认参数及其格式](https://github.com/PKU-Alignment/omnisafe/tree/main/omnisafe/configs)请参见GitHub repo。\n",
    "\n",
    "下面的代码在`SafetyPointGoal1-v0`上运行了两个`epoch`，共`2048`步交互，每`1024`步更新策略。环境并行和线程并行都设置为`1`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "vxbrupSD5cJK"
   },
   "outputs": [],
   "source": [
    "import omnisafe\n",
    "\n",
    "\n",
    "env_id = 'SafetyPointGoal1-v0'\n",
    "custom_cfgs = {\n",
    "    'train_cfgs': {\n",
    "        'total_steps': 2048,\n",
    "        'vector_env_nums': 1,\n",
    "        'parallel': 1,\n",
    "    },\n",
    "    'algo_cfgs': {\n",
    "        'steps_per_epoch': 1024,\n",
    "        'update_iters': 1,\n",
    "    },\n",
    "    'logger_cfgs': {\n",
    "        'use_wandb': False,\n",
    "    },\n",
    "}\n",
    "\n",
    "agent = omnisafe.Agent('TRPO', env_id, custom_cfgs=custom_cfgs)\n",
    "agent.learn()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "27tsIfmo7rd9"
   },
   "source": [
    "### Render and evaluate your policy\n",
    "\n",
    "RL在过去取得了长足进步，立足于当今，我们认为不能仅通过智能体的累积回报来评价算法的性能优劣。而是应当更看重智能体的学习是否产生了有意义的行为，尤其是当Safe的因素被纳入考虑时，更应该关注智能体是否能实际产生带有安全约束的决策序列。\n",
    "\n",
    "因此，OmniSafe支持快速render和evaluate策略模型，当训练完成之后，您可以轻松地对结果进行可视化，在OmniSafe当中完成一站式工作流，节省宝贵的时间。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "BUkkson3Co65"
   },
   "source": [
    "下面这行代码将会绘制上方训练完毕agent的训练曲线图，展示整个训练过程中reward和cost随着交互次数的变化情况。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "w8_WGipx-lA0"
   },
   "outputs": [],
   "source": [
    "agent.plot(smooth=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "o0SDM8tkC2bx"
   },
   "source": [
    "看完曲线图，不管是对结果满意还是失望，您一定想了解是什么样的行为导致了这样的曲线。因此，OmniSafe支持了从训练到可视化和数据分析的整个工作流。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gxX84UBkXZ7i"
   },
   "source": [
    "在云容器上运行可视化，需要一些额外依赖。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "QuIAV2k7rUzu"
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "apt-get install libosmesa6-dev\n",
    "apt-get install python3-opengl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "SWbnhykqZTO1"
   },
   "outputs": [],
   "source": [
    "%env MUJOCO_GL=osmesa\n",
    "%env PYOPENGL_PLATFORM=osmesa"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "bPSz0C8CDApD"
   },
   "outputs": [],
   "source": [
    "agent.render(num_episodes=1, render_mode='rgb_array', width=256, height=256)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "NyEhctNbt2Qx"
   },
   "source": [
    "将上面给出的视频文件路径填入下面播放试试看！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "0cTAss1RuFYn"
   },
   "outputs": [],
   "source": [
    "import base64\n",
    "from pathlib import Path\n",
    "\n",
    "from IPython import display as ipythondisplay\n",
    "\n",
    "\n",
    "def show_videos(video_path='', prefix=''):\n",
    "    \"\"\"\n",
    "    Taken from https://github.com/eleurent/highway-env\n",
    "\n",
    "    :param video_path: (str) Path to the folder containing videos\n",
    "    :param prefix: (str) Filter the video, showing only the only starting with this prefix\n",
    "    \"\"\"\n",
    "    html = []\n",
    "    for mp4 in Path(video_path).glob(\"{}*.mp4\".format(prefix)):\n",
    "        video_b64 = base64.b64encode(mp4.read_bytes())\n",
    "        html.append(\n",
    "            '''<video alt=\"{}\" autoplay \n",
    "                    loop controls style=\"height: 400px;\">\n",
    "                    <source src=\"data:video/mp4;base64,{}\" type=\"video/mp4\" />\n",
    "                </video>'''.format(\n",
    "                mp4, video_b64.decode('ascii')\n",
    "            )\n",
    "        )\n",
    "    ipythondisplay.display(ipythondisplay.HTML(data=\"<br>\".join(html)))\n",
    "\n",
    "\n",
    "# Please fill the path of folder containing your video which is shown above here\n",
    "show_videos(video_path='')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "muSYZV_-DCLW"
   },
   "source": [
    "或者，您只是想看看收敛后的策略在test时数值表现如何。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "rMD6j5sADOaz"
   },
   "outputs": [],
   "source": [
    "agent.evaluate(num_episodes=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "yqQmc_ODDY5T"
   },
   "source": [
    "我们希望提供丰富的信息以便您可以收获新的见解。通过上述方法，您可以从不同角度了解这次实验。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "id": "TrBRWG9c-2Dw"
   },
   "source": [
    "当然，您也可以对过去保存的策略进行分析。嘿！试试看将上面保存的策略路径粘贴到下面。这段脚本是Evaluator的最常见用法，它会将给定的实验路径下所有模型都按照指定方式可视化。通常，**这段代码在您个人的服务器上会比在colab当中更为灵活有用**。\n",
    "\n",
    "通过修改代码，您可以可视化任意路径下的模型文件。有几个重要的参数，理解它们对可视化至关重要。\n",
    "\n",
    "`render_mode`:该参数指定可视化时显示的方式，通常有`rgb_array`, `depth_array`, `human`。您在没有显示屏的服务器上指定它们时，可能会遇到麻烦，请参考[issue72](https://github.com/PKU-Alignment/omnisafe/issues/72)以及[issue27](https://github.com/PKU-Alignment/omnisafe/issues/27)。\n",
    "\n",
    "`camera_name`:其取值取决于环境库的设计，在Safety-Gymnasium当中，支持了[这些](https://www.safety-gymnasium.com/en/latest/api/builder.html#safety_gymnasium.builder.Builder.__init__)。\n",
    "\n",
    "`width`，`height`: 这两个参数用于指定图像分辨率，数值越大，画面质量越高，同时，对硬件资源的要求也会大幅增长，建议您根据自身硬件资源尝试之后，选定符合自己需求的值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "vaVHC5WK-1CT"
   },
   "outputs": [],
   "source": [
    "# Single Python File\n",
    "import os\n",
    "import omnisafe\n",
    "\n",
    "# Just fill your experiment's log directory in here.\n",
    "# Such as: ~/omnisafe/examples/runs/PPOLag-{SafetyPointGoal1-v0}/seed-000-2023-03-07-20-25-48\n",
    "LOG_DIR = './runs/PPOLag-{SafetyPointGoal1-v0}/seed-000-2023-04-01-02-44-35'\n",
    "evaluator = omnisafe.Evaluator(render_mode='rgb_array')\n",
    "for item in os.scandir(os.path.join(LOG_DIR, 'torch_save')):\n",
    "    if item.is_file() and item.name.split('.')[-1] == 'pt':\n",
    "        evaluator.load_saved(\n",
    "            save_dir=LOG_DIR, model_name=item.name, camera_name='track', width=256, height=256\n",
    "        )\n",
    "        evaluator.render(num_episodes=1)\n",
    "        evaluator.evaluate(num_episodes=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3Gl1f0kgG8ea"
   },
   "source": [
    "### Benchmark your research\n",
    "在研究的过程中，运行大量实验通常是一项繁重且易错的体力劳动，为了让研究者能够专注于有价值的劳动，OmniSafe提供了`experiment grid`模块，借助它，您只需要对感兴趣的参数给出所有可选的参数值，即可快速可靠地运行大批量的实验，无论是为自己的算法做基线，还是需要调参，都会得到极大方便。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "id": "gWxhptNhIsy6"
   },
   "source": [
    "从实现原理上，您可以简单地将其理解为：\n",
    "1. 自动生成了所有可行的参数组合。\n",
    "2. 使用python的多进程工具，按照指定的并行数量，用不同的参数同时执行相同的函数。\n",
    "\n",
    "因此，您需要定义好一个需要通过`experiment_grid`执行的函数，这件事我们已经为您做好了，可以直接复制我们的例子，或者您可以参考GitHub当中的[例子](https://github.com/PKU-Alignment/omnisafe/tree/main/examples)，其中包含了本节当中讲述的几乎所有内容的代码示例。\n",
    "\n",
    "注意：您不用关注这段代码的实现细节，仅当您有高度定制化的需求时需要对它进行修改。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "o4ZijAqvIWMK"
   },
   "outputs": [],
   "source": [
    "\"\"\"Example of training a policy from exp-x config with OmniSafe.\"\"\"\n",
    "\n",
    "import os\n",
    "import sys\n",
    "import warnings\n",
    "\n",
    "import torch\n",
    "\n",
    "import omnisafe\n",
    "from omnisafe.common.experiment_grid import ExperimentGrid\n",
    "from omnisafe.typing import NamedTuple, Tuple\n",
    "\n",
    "\n",
    "def train(\n",
    "    exp_id: str, algo: str, env_id: str, custom_cfgs: NamedTuple\n",
    ") -> Tuple[float, float, float]:\n",
    "    \"\"\"Train a policy from exp-x config with OmniSafe.\n",
    "\n",
    "    Args:\n",
    "        exp_id (str): Experiment ID.\n",
    "        algo (str): Algorithm to train.\n",
    "        env_id (str): The name of test environment.\n",
    "        custom_cfgs (NamedTuple): Custom configurations.\n",
    "        num_threads (int, optional): Number of threads. Defaults to 6.\n",
    "    \"\"\"\n",
    "    terminal_log_name = 'terminal.log'\n",
    "    error_log_name = 'error.log'\n",
    "    if 'seed' in custom_cfgs:\n",
    "        terminal_log_name = f'seed{custom_cfgs[\"seed\"]}_{terminal_log_name}'\n",
    "        error_log_name = f'seed{custom_cfgs[\"seed\"]}_{error_log_name}'\n",
    "    sys.stdout = sys.__stdout__\n",
    "    sys.stderr = sys.__stderr__\n",
    "    print(f'exp-x: {exp_id} is training...')\n",
    "    if not os.path.exists(custom_cfgs['logger_cfgs']['log_dir']):\n",
    "        os.makedirs(custom_cfgs['logger_cfgs']['log_dir'], exist_ok=True)\n",
    "    # pylint: disable-next=consider-using-with\n",
    "    sys.stdout = open(\n",
    "        os.path.join(f'{custom_cfgs[\"logger_cfgs\"][\"log_dir\"]}', terminal_log_name),\n",
    "        'w',\n",
    "        encoding='utf-8',\n",
    "    )\n",
    "    # pylint: disable-next=consider-using-with\n",
    "    sys.stderr = open(\n",
    "        os.path.join(f'{custom_cfgs[\"logger_cfgs\"][\"log_dir\"]}', error_log_name),\n",
    "        'w',\n",
    "        encoding='utf-8',\n",
    "    )\n",
    "    agent = omnisafe.Agent(algo, env_id, custom_cfgs=custom_cfgs)\n",
    "    reward, cost, ep_len = agent.learn()\n",
    "    return reward, cost, ep_len"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "QUX4saAoJoiR"
   },
   "source": [
    "接着，创建`experiment grid`实例并且调用`eg.add`指定您的参数，多个参数请通过list存放。\n",
    "\n",
    "注意：是不是叫`eg`取决于您为`experiment grid`实例指定的变量名。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "t1f4lMz6JtK2"
   },
   "outputs": [],
   "source": [
    "eg = ExperimentGrid(exp_name='Tutorial_benchmark')\n",
    "\n",
    "# Set the algorithms.\n",
    "base_policy = ['PolicyGradient', 'NaturalPG', 'TRPO', 'PPO']\n",
    "\n",
    "# Set the environments.\n",
    "mujoco_envs = [\n",
    "    'SafetyAntVelocity-v1',\n",
    "    'SafetyHopperVelocity-v1',\n",
    "    'SafetyHumanoidVelocity-v1',\n",
    "]\n",
    "eg.add('env_id', mujoco_envs)\n",
    "\n",
    "\n",
    "eg.add('algo', base_policy)\n",
    "eg.add('logger_cfgs:use_wandb', [False])\n",
    "eg.add('train_cfgs:vector_env_nums', [1])\n",
    "eg.add('train_cfgs:torch_threads', [1])\n",
    "eg.add('train_cfgs:total_steps', [2048])\n",
    "eg.add('algo_cfgs:steps_per_epoch', [1024])\n",
    "eg.add('seed', [0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "nYVD1pL1LK96"
   },
   "source": [
    "CUDA是机器学习强有力的加速工具，我们也为其提供了支持，您可以将实验均匀分散到多个GPU当中执行，在此处仅仅给出一个示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "Om1yCcDgLYVX"
   },
   "outputs": [],
   "source": [
    "# # Set the device.\n",
    "# avaliable_gpus = [num for num in range(torch.cuda.device_count())]\n",
    "# gpu_id = [0, 1, 2, 3]\n",
    "# # if you want to use CPU, please set gpu_id = None\n",
    "# # gpu_id = None\n",
    "\n",
    "# if set(gpu_id) > set(avaliable_gpus):\n",
    "#     warnings.warn('The GPU ID is not available, use CPU instead.')\n",
    "#     gpu_id = None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "I8f2t0PZLfOK"
   },
   "source": [
    "接下来，您可以指定同时并行的进程数目，充分利用机器吧！\n",
    "\n",
    "必须要提示的一点是，我们推荐将`num_pool`的值设定为可以整除总任务数的一个值，这样可以保证您的计算机在每一个时刻负载的任务数尽可能相同，可以最大程度地利用算力。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "VvinJv_3Lnv8"
   },
   "outputs": [],
   "source": [
    "# total experiment num must can be divided by num_pool\n",
    "# meanwhile, users should decide this value according to their machine\n",
    "eg.run(train, num_pool=12)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "PfexgqIIMBz9"
   },
   "source": [
    "若是使用CUDA，调用方式会略有不同，需要传入`gpu_id`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "Gf5o7vx6MFd5"
   },
   "outputs": [],
   "source": [
    "# eg.run(train, num_pool=12, gpu_id=gpu_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Jcx0SRyQKm51"
   },
   "source": [
    "训练完成后，您可以通过之前提到过的一些数据分析工具来从不同角度批量分析实验结果，这些工具都是独立的模块，可以在训练完成的同时调用，也可以在训练完成后单独调用。我们还会在后面的章节中详细介绍如何**灵活地单独使用和组合**这些模块。\n",
    "\n",
    "下面的代码块中，您可以指定一个参数，并分析该参数的不同取值对性能产生的影响。\n",
    "\n",
    "`parameter`: 指定需要分析取值影响的参数。\n",
    "\n",
    "`values`: 指定需要显示在同一张图上进行对比的几种取值。\n",
    "\n",
    "`compare_num`: 指定同一张图上最多想显示多少种取值进行对比。\n",
    "\n",
    "`cost_limit`: 指定绘制在图上的cost阈值。\n",
    "\n",
    "注意：`values`和`compare_num`是一对冲突的参数，不可以同时指定，若同时取None，则默认将`compare_num`取可行的最大值。\n",
    "\n",
    "下面将演示两种可能的用法："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Ii2gOSASOYtH"
   },
   "source": [
    "1. 指定取值进行分析。\n",
    "\n",
    "我们已经在3个环境上运行完成了我们的benchmark，现在我们希望比较PPO和PolicyGradient在不同环境上的性能如何。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "lOOQkviDKovM"
   },
   "outputs": [],
   "source": [
    "# just fill in the name of the parameter of which value you want to compare.\n",
    "# then you can specify the value of the parameter you want to compare,\n",
    "# or you can just specify how many values you want to compare in single graph at most,\n",
    "# and the function will automatically generate all possible combinations of the graph.\n",
    "# but the two mode can not be used at the same time.\n",
    "eg.analyze(parameter='algo', values=['PPO', 'PolicyGradient'], compare_num=None, cost_limit=None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "__2JC1gCO4iY"
   },
   "source": [
    "2. 对比所有可能的情况，找出最好的算法。\n",
    "\n",
    "辛苦工作了一天，我们不想同时面对理不清的曲线，那么让大脑放松一会吧，您可以要求在一张图片上最多同时对比三个算法，OmniSafe会为您自动生成当前实验中所有可能的包含三个算法的图片。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "2u22rNv7M4HP"
   },
   "outputs": [],
   "source": [
    "eg.analyze(parameter='algo', values=None, compare_num=3, cost_limit=None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "u-Tsi7S8QS2t"
   },
   "source": [
    "当然，跟之前一样，您也可以对所有的模型进行可视化，放心把一切繁杂的工作交给OmniSafe，只需要审阅最终的结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "K6bHQYqfQdXY"
   },
   "outputs": [],
   "source": [
    "eg.render(num_episodes=1, render_mode='rgb_array', width=256, height=256)\n",
    "eg.evaluate(num_episodes=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "CeEEKZWtSVdH"
   },
   "source": [
    "当然，您同样也可以单独通过Python代码调用该工具对过去的实验进行分析。下面展示一个简单的例子。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "AL36B-XySdw2"
   },
   "outputs": [],
   "source": [
    "# Single Python File\n",
    "from omnisafe.common.statistics_tools import StatisticsTools\n",
    "\n",
    "\n",
    "# just fill in the path in which experiment grid runs.\n",
    "path = ''\n",
    "st = StatisticsTools()\n",
    "st.load_source(path)\n",
    "# just fill in the name of the parameter of which value you want to compare.\n",
    "# then you can specify the value of the parameter you want to compare,\n",
    "# or you can just specify how many values you want to compare in single graph at most,\n",
    "# and the function will automatically generate all possible combinations of the graph.\n",
    "# but the two mode can not be used at the same time.\n",
    "st.draw_graph(parameter='', values=None, compare_num=2, cost_limit=None, show_image=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "do9X-8qrTDSG"
   },
   "source": [
    "通过上面的示例与讲解，您已经掌握了OmniSafe的基本用法，下一节当中，我们将会为您介绍OmniSafe当中的CLI工具。"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "authorship_tag": "ABX9TyOD2mcjnlbrLWq4wO9NPMXS",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
